package com.dd.cloud.open.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.open.constants.UserConstants;
import com.dd.cloud.open.entity.OpenUserApply;
import com.dd.cloud.open.enums.ResponseEnum;
import com.dd.cloud.open.exception.ApiException;
import com.dd.cloud.open.mapper.OpenUserApplyMapper;
import com.dd.cloud.open.service.IOpenUserApplyService;
import com.dd.cloud.open.utils.CodecUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * @author Lx
 * @version 1.0
 * @date 2023/9/11
 */
@Slf4j
@Service
public class OpenUserApplyServiceImpl extends ServiceImpl<OpenUserApplyMapper, OpenUserApply> implements IOpenUserApplyService {

    private RedisTemplate<String, String> redisTemplate;

    @Resource
    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 生成用户 开发者ID 开发者密码
     *
     * @param userId
     */
    @Override
    public void createOpenUserApply(Integer userId) {
        QueryWrapper<OpenUserApply> qw = new QueryWrapper<>();
        qw.lambda().eq(OpenUserApply::getUserId, userId);
        qw.lambda().ne(OpenUserApply::getStatus, UserConstants.OpenUserApplyStatus.DELETE);
        int count = count(qw);
        if (count > 0) {
            return;
        }
        OpenUserApply oua = new OpenUserApply();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        uuid = uuid.substring(0, 16).toLowerCase() + uuid.substring(16, 32).toUpperCase();
        String appId = "dd" + CodecUtils.md5Hex(uuid, userId + "").substring(8, 24);
        uuid = UUID.randomUUID().toString().replace("-", "");
        uuid = uuid.substring(0, 16).toLowerCase() + uuid.substring(16, 32).toUpperCase();
        String appSecret = CodecUtils.md5Hex(uuid, appId);
        oua.setAppId(appId);
        oua.setAppSecret(appSecret);
        oua.setUserId(userId);
        oua.setGenerateNum(1);
        oua.setCreateDate(LocalDateTime.now());
        oua.setStatus(UserConstants.OpenUserApplyStatus.READABLE);
        boolean flag = save(oua);
        if (!flag) {
            throw new ZekeException(400, "生成开发者id,开发者密码失败");
        }
    }

    /**
     * 重置用户开发者密码
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public String resetUserApplySecret(Integer userId) {
        if (userId == null) {
            throw new ZekeException(400, "用户id不能为空");
        }
        QueryWrapper<OpenUserApply> qw = new QueryWrapper<>();
        qw.lambda().select(OpenUserApply::getGenerateNum);
        qw.lambda().eq(OpenUserApply::getUserId, userId);
        qw.lambda().ne(OpenUserApply::getStatus, UserConstants.OpenUserApplyStatus.DELETE);
        OpenUserApply oua = getOne(qw);
        if (oua == null) {
            throw new ZekeException(400, "信息异常");
        }
        Integer generateNum = oua.getGenerateNum() + 1;
        String uuid = UUID.randomUUID().toString().replace("-", "");
        uuid = uuid.substring(0, 16).toLowerCase() + uuid.substring(16, 32).toUpperCase();
        String appSecret = CodecUtils.md5Hex(uuid, oua.getAppId());
        oua = new OpenUserApply();
        oua.setAppSecret(appSecret);
        oua.setGenerateNum(generateNum);
        oua.setStatus(UserConstants.OpenUserApplyStatus.UN_READABLE);
        boolean flag = update(oua, qw);
        if (!flag) {
            throw new ZekeException(400, "重置开发者密码失败");
        }
        return appSecret;
    }

    /**
     * 验证用户开发者账号
     *
     * @param appId     开发者id
     * @param sign      签名
     * @param timestamp 请求时间戳
     * @return
     */
    @Override
    public Integer verifyUserApp(String appId, String sign, Long timestamp) {
        long currentTimeMillis = System.currentTimeMillis();
        if ((currentTimeMillis - timestamp) > 30000 || currentTimeMillis < timestamp) {
            throw new ApiException(ResponseEnum.SIGN_INVALID);
        }
        Integer userId = -1;
        String appSecret = redisTemplate.opsForValue().get(appId);
        if (StringUtils.isBlank(appSecret)) {
            QueryWrapper<OpenUserApply> qw = new QueryWrapper<>();
            qw.lambda().eq(OpenUserApply::getAppId, appId);
            qw.lambda().ne(OpenUserApply::getStatus, UserConstants.OpenUserApplyStatus.DELETE);
            OpenUserApply oua = getOne(qw);
            if (oua != null) {
                redisTemplate.opsForValue().set(oua.getAppId(), oua.getUserId() + "-" + oua.getAppSecret());
                userId = oua.getUserId();
                appSecret = oua.getAppSecret();
            }
        } else {
            String[] arr = appSecret.split("-");
            userId = Integer.valueOf(arr[0]);
            appSecret = arr[1];
        }
        String verifySign = CodecUtils.md5Hex(appSecret + timestamp);
        if (!sign.equals(verifySign)) {
            return -1;
        }
        return userId;
    }
}
